import java.awt.Desktop;
import java.io.BufferedWriter;
import java.io.Console;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.sql.Timestamp;

import javax.print.Doc;
import javax.print.DocFlavor;
import javax.print.DocPrintJob;
import javax.print.PrintException;
import javax.print.PrintService;
import javax.print.PrintServiceLookup;
import javax.print.SimpleDoc;
import javax.print.attribute.AttributeSet;
import javax.print.attribute.HashPrintRequestAttributeSet;
import javax.print.attribute.PrintRequestAttributeSet;
import javax.print.attribute.standard.MediaSizeName;
import javax.print.attribute.standard.PrinterState;
import javax.print.attribute.standard.PrinterStateReason;


public class MultiPrint {

	public static boolean ABORT = false;
	public static boolean NIGHT = false;
	public static String SEP = File.separator;
 
	
	public static void main(String[] args) {
		
		  String path= null,currentFilePath; 
		  String printer = null;

		  //Checks for the arguments
		  if(args.length<1)
		  {
			  System.out.println("A path to a directory is needed.");
			  hangOn();
			  System.exit(0);
		  }
		  if(args.length>4)
		  {
			  System.out.println("Too many parameters");
			  hangOn();
			  System.exit(0);
		  }
		  
		  if(argDirExists(args[0]))
		  {
			  path=args[0];
		  }
		  else
		  {
			  hangOn();
			  System.exit(0);

		  }
		  if(argPrnExists(args))
		  {
			  printer = getArgPrn(args);
			  if(checkDefaultPrinter(printer)==false)
			  {
				  System.out.println("Printer "+printer+" is not the default printer!");
				  hangOn();
				  System.exit(0);
			  }
		  }
		  else
		  {
			  hangOn();
			  System.exit(0);

		  }
		  if(argNExists(args)==true)
		  {
			  NIGHT = true;
		  }
		  
		  //
		  
		  
		  currentFilePath = path;
		  Boolean successFlag = false;		  
		  String files;
		  File folder = new File(path);
		  File[] listOfFiles = folder.listFiles(); 
		  	  
		  if(checkDefaultPrinter(printer)==true)
		  {
			  System.out.println("=====Start=====");
			  for (int i = 0; i < listOfFiles.length; i++) 
			  {
				  currentFilePath = path;
			   if (listOfFiles[i].isFile()) 
			   {
				   	files = listOfFiles[i].getName();
			       
			   	   	currentFilePath = currentFilePath +SEP+files;
			   		
			   		if (files.endsWith(".doc") || files.endsWith(".DOC")
			    		   ||files.endsWith(".docx")||files.endsWith(".DOCX"))
			   		{
			   		  
			   			do
			   			{
			   				successFlag = printDoc(currentFilePath);	
			   				
			   			}  	while(successFlag == false && ABORT == false);
			   			
			   			
				   		 if(ABORT == true)
				   		  {
				   			  break;
				   		  }
				   		 	//Deletes fine, uncomment when ready
				   		  //listOfFiles[i].delete();
				   		
				   		  do
					   		 {
					   			  try 
					   			  {
									Thread.sleep(1000);
					   			  } 
					   			  catch (InterruptedException e) 
					   			  {
										e.printStackTrace();
					   			  }
					   		 } while(printerReady() == false);
				   		  
			        }
			     }
			   currentFilePath = null;
			   
			  }
			  System.out.println("=====End=====");
			  
		  }
	
		 hangOn();
	}


	
	//Prints a document
	public static boolean printDoc(String currentFile) 
	{
		boolean flag = true;
		if(currentFile == null)
		{
			System.out.println("No document given!");
		}
		else
		{	
			String content;
			
			try 
			   {
			      Desktop desktop = null;
			      if (Desktop.isDesktopSupported()) 
			      {
			        desktop = Desktop.getDesktop();
			      }
			      
			      desktop.print(new File(currentFile));
			      content = "File: "+currentFile+" printed successfully!";
			      System.out.println(content);
			      updateLog(content);		      
			      flag = true;
			   } 
			  catch (IOException ioe) 
			   {
			       content ="File: "+currentFile+" printing FAILED!";
				   System.out.println(content);
			       updateLog(content);	
			       flag = false;
			       if(NIGHT == false)
			       {
			    	   	abortPrint();
			       }
			       else
			       {
			    	   ABORT = true;
			       }
			       
			    	//ioe.printStackTrace();
			   }
			
		}
		return flag;
	}
		
	//Shows the available printers
	public static void showPrinters() {
		PrintService[] services = PrintServiceLookup.lookupPrintServices(null, null);
		if(services.length < 1)
		{
			System.out.println("Zero printers found!");
		}
		for (int i = 0; i < services.length; i++) {
		   System.out.println(services[i].getName());
		}
	}

	//checks if a certain printer is the default printer
	public static boolean checkDefaultPrinter(String trgPrinter)
	{
		PrintService service = PrintServiceLookup.lookupDefaultPrintService();
		
		String str=null;	
		
		if(service != null)
		{
			str = service.getName();
			
		}
		
		if(str.contains(trgPrinter))
		{
			return true;
		}
		else if(str.isEmpty())
		{
			
			return false;
		}
		else
		{
			return false;
		}
	}
	
	//checks if there is a printer
	public static boolean checkDefaultPrinter()
	{
		PrintService service = PrintServiceLookup.lookupDefaultPrintService();
				
		if(service == null)
		{
			return false;
		}
		
		return true;
	}
	
	public static void printing()//CODE EXAMPLE. DOES NOT RUN!!!!!!!!!!
	{
		DocFlavor psFlavor = DocFlavor.INPUT_STREAM.AUTOSENSE;
        PrintRequestAttributeSet aset = new HashPrintRequestAttributeSet();
        aset.add(MediaSizeName.ISO_A4);

        PrintService[] pservices = PrintServiceLookup.lookupPrintServices(psFlavor, aset);
        if (pservices.length > 0) {
                DocPrintJob pj = pservices[0].createPrintJob();
                try {
                        FileInputStream fis = new FileInputStream("document 1.docx");
                        Doc doc = new SimpleDoc(fis, psFlavor, null);
                        pj.print(doc, aset);
                } catch (IOException e) {
                        System.err.println(e);
                } catch (PrintException e) {
                        System.err.println(e);
                }
        }
	}
	
	//Prints the documents in a specific printer //OBSELETE
	public static void printFile(String filename) 
	{  
				
		boolean flag;
		flag = checkDefaultPrinter();
		if(flag == true)
		{
			//showPrinters();
			printDoc(filename);
			
		}

	}
	
	public static String printerStatus()
	{
		PrintService printService = PrintServiceLookup.lookupDefaultPrintService();
		AttributeSet attributes = printService.getAttributes();
		
		String printerState = attributes.get(PrinterState.class).toString();
		String printerStateReason = attributes.get(PrinterStateReason.class).toString();

		
		// May be IDLE, PROCESSING, STOPPED or UNKNOWN
		System.out.println("printerState = " + printerState); 
		// If your printer state returns STOPPED, for example, you can identify the reason 
		System.out.println("printerStateReason = " + printerStateReason); 

		if (printerState.equals(PrinterState.STOPPED.toString())) {

		    if (printerStateReason.equals(PrinterStateReason.TONER_LOW.toString())) 
		    {
		        System.out.println("Toner level is low.");
		    }

			if(printerState.equals(PrinterState.IDLE.toString()))
			{
				return "IDLE";
			}
			
		}

		return printerState;
		
		

		
	}

	public static boolean printerReady()
	{
		
		boolean flag= true;
		
		PrintService printService = PrintServiceLookup.lookupDefaultPrintService();
		AttributeSet attributes = printService.getAttributes();
		String printerState = null;
		
		if(attributes.get(PrinterState.class) != null)
		{
			printerState = attributes.get(PrinterState.class).toString();
			
			if(printerState.equals(PrinterState.IDLE.toString()))
			{
				flag = true;
			}
			else if(printerState.equals(PrinterState.PROCESSING.toString()))
			{
				flag = false;
			}
			else if(printerState.equals(PrinterState.STOPPED.toString()))
			{
				flag = false;
			}
			else if(printerState.equals(PrinterState.UNKNOWN.toString()))
			{
				flag = true;
			}
		}	
				
		return flag;
	}

	public static void printerFault()//shows what problem the printer has
	{
		PrintService printService = PrintServiceLookup.lookupDefaultPrintService();
		AttributeSet attributes = printService.getAttributes();
		String printerState = null;
		String printerStateReason = null;
		if(attributes.get(PrinterState.class) != null)
		{
			printerState = attributes.get(PrinterState.class).toString();
			printerStateReason = attributes.get(PrinterStateReason.class).toString();
		
			
			if(printerState.equals(PrinterState.STOPPED.toString()))
			{
				// If the printer state returns STOPPED we identify the reason 		
				System.out.println("Printer stopped: " + printerStateReason); 
			}
		}
	}
	
	public static String[] getPrinters()
	{
		PrintService[] services = PrintServiceLookup.lookupPrintServices(null, null);

		String[] printers = null;
		int length = services.length;
		
		if(services.length < 1)
		{
			System.out.println("Zero printers found!");
			return null;
		}
		else
		{
			printers = new String[length];
			
			for (int i = 0; i < length; i++) 
			{
				//System.out.println(services[i].getName());
				printers[i] = services[i].getName();
		   
			}
			return printers;
		}
		
	}
	
	public static void abortPrint()
	{
		Console console = System.console();
		printerFault();
		String choice = console.readLine("Continue? y/n: ");
		if(choice.startsWith("n"))
		{
			ABORT = true;
		}
		else
		{
			ABORT = false;
		}
	}
	
	//update the log with all operations
	public static void updateLog(String content) 

	{
		
		 java.util.Date date= new java.util.Date();
		 String timestamp = new Timestamp(date.getTime()).toString();
		 
		 
		try {
			String path = System.getProperty("user.dir");
			File file = new File(path+SEP+"log.txt");
 
			// if file doesnt exists, then create it
			if (!file.exists()) {
				file.createNewFile();
			}
			
			content = timestamp + " --- " + content;
			FileWriter fw = new FileWriter(file.getAbsoluteFile(),true);
			BufferedWriter bw = new BufferedWriter(fw);
			bw.newLine();
			bw.append(content);
			bw.close();
 
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		
	}
	
	//Checks if the given directory exists
	public static boolean argDirExists(String argStr)
	{
		
		File dir = new File(argStr);
		
		if (argStr != null && dir.isDirectory() == true)
		{
			//System.out.println("Dir: "+argStr);

			return true;
		}
		else 
		{
			System.out.println("Please enter a valid path.");
		}
		return false;
	}
	
	//Checks if a parameter printer is given and is correct
	public static boolean argPrnExists(String[] argStr)
	{
		int i,j;
		for(i=0;i<argStr.length;i++)
		{
			if(argStr[i].startsWith("-p"))
			{
				j=i+1;
				//System.out.println("Found -p: "+argStr[j]);
				if(argStr[j] == null)
				{
					System.out.println("Error - No argument given");
					return false;
				}
				if(checkPrnName(argStr[j])==true)
				{
					return true;
				}
				else 
				{
					System.out.println("Error - No such printer found");
					return false;
				}
			}
		}
		
		return false;
	}

	//Returns the printer name that corresponds from the one in the argument. 
	public static String getArgPrn(String[] argStr)
	{
		
		String prnName;
		int i,j;
		for(i=0;i<argStr.length;i++)
		{
			if(argStr[i].startsWith("-p"))
			{
				j = i+1;
				 prnName = getPrinterName(argStr[j]);
				 return prnName;
			}
		}		
		return null;
	}
	
	//Checks if the Night Operation option is enabled
	public static boolean argNExists(String[] argStr)
	{
		int i;
		for(i=0;i<argStr.length;i++)
		{
			if(argStr[i].startsWith("-n"))
			{
				return true;
			}
		}
		
		return false;
	}
		
	/*=======================================
	 * 			UTILITIES
	 ========================================*/

	//shows the arguments
	public static void showArgs(String[] argStr)
	{
		int i,length;
		length = argStr.length;
		
		for(i=0;i<length;i++)
		{
			System.out.println("Arg["+i+"]: "+argStr[i]);
		}
	}
	
	//Checks if the printer name given in the argument exists
	public static boolean checkPrnName(String prn)
	{
		String[] printers = getPrinters();
		for(int i=0;i<printers.length;i++)
		{
			if(printers[i].contains(prn))
			{
				return true;
			}
		}
		return false;
	}

	//Return the printer name that correspond more to the name given
	public static String getPrinterName(String prn)
	{
		String[] printers = getPrinters();
		for(int i=0;i<printers.length;i++)
		{
			if(printers[i].contains(prn))
			{
				return printers[i];
			}
		}
		return null;
	}
	
	public static void hangOn()
	{
		try {
			System.out.println("Press any key....");
			System.in.read();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	
}
